package com.egg.common.spring.config;

import cn.hutool.core.date.DatePattern;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.egg.common.core.model.controller.ApiController;
import com.egg.common.core.model.controller.ExternalController;
import com.egg.common.core.model.controller.FeignController;
import com.egg.common.core.model.controller.WebController;
import com.egg.common.spring.filter.SensitiveFilter;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.format.datetime.standard.DateTimeFormatterRegistrar;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @author east
 */
@Configuration
public class WebMvcConfigurationSupportConfig extends WebMvcConfigurationSupport {


    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        // 解决静态资源无法访问
        registry.addResourceHandler("/statics/**").addResourceLocations("classpath:/static/");
        //过滤swagger
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
        registry.addResourceHandler("/**/v2/api-docs").addResourceLocations("classpath:/META-INF/resources/v2/api-docs/");
        registry.addResourceHandler("/swagger/**", "/swagger-resources/**", "/**/swagger-ui.html", "/**/doc.html").addResourceLocations("classpath:/META-INF/resources/");
    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        // 需要定义一个convert转换消息的对象;
        FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
        // 添加fastJson的配置信息;
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        // LocalDateTime 与 Date 使用 @JSONField 注解优先以注解为准,否则展示全局设置 yyyy-MM-dd HH:mm:ss
        fastJsonConfig.setSerializerFeatures(
                SerializerFeature.PrettyFormat
                , SerializerFeature.WriteDateUseDateFormat
                , SerializerFeature.DisableCircularReferenceDetect
        );
        //防止失真
        //SerializeConfig serializeConfig = SerializeConfig.getGlobalInstance();
        //serializeConfig.put(Long.class, ToStringSerializer.instance);
        //serializeConfig.put(Long.TYPE, ToStringSerializer.instance);
        //fastJsonConfig.setSerializeConfig(serializeConfig);

        fastConverter.setDefaultCharset(StandardCharsets.UTF_8);
        fastConverter.setFastJsonConfig(fastJsonConfig);
        //脱敏拦截器
        fastJsonConfig.setSerializeFilters(new SensitiveFilter());

        // 处理中文乱码问题
        List<MediaType> fastMediaTypes = new ArrayList<>();
        fastMediaTypes.add(MediaType.APPLICATION_JSON);
        // 在convert中添加配置信息.
        fastConverter.setSupportedMediaTypes(fastMediaTypes);
        converters.add(fastConverter);
    }

    /**
     * 增加GET请求参数中时间类型转换
     * <ul>
     * <li>HH:mm:ss -> LocalTime</li>
     * <li>yyyy-MM-dd -> LocalDate</li>
     * <li>yyyy-MM-dd HH:mm:ss -> LocalDateTime</li>
     * </ul>
     *
     * @param registry
     */
    @Override
    public void addFormatters(FormatterRegistry registry) {
        DateTimeFormatterRegistrar dateTime = new DateTimeFormatterRegistrar();
        dateTime.setTimeFormatter(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN));
        dateTime.setDateFormatter(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN));
        dateTime.setDateTimeFormatter(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN));
        dateTime.registerFormatters(registry);
    }

    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
        JavaTimeModule module = new JavaTimeModule();
        LocalDateTimeDeserializer localDateTimeDeserializer = new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN));
        module.addDeserializer(LocalDateTime.class, localDateTimeDeserializer);
        // 防止失真
        module.addSerializer(Long.class, ToStringSerializer.instance);
        module.addSerializer(Long.TYPE, ToStringSerializer.instance);
        return builder -> {
            builder.simpleDateFormat(DatePattern.NORM_DATETIME_PATTERN);
            builder.serializers(new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
            builder.serializers(new LocalDateSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)));
            builder.serializers(new LocalTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN)));
            /*
                通过该方法对mapper对象进行设置，所有序列化的对象都将按改规则进行系列化
                 Include.Include.ALWAYS 默认
                 Include.NON_DEFAULT 属性为 默认值 不序列化
                 Include.NON_EMPTY 属性为 空（""） 或者为 NULL 不序列化
                 Include.NON_NULL 属性为 NULL 不序列化
             */
            builder.serializationInclusion(JsonInclude.Include.NON_NULL);
            builder.modules(module);
        };
    }

    /**
     * 添加统一前缀
     * -- [电脑端]统一添加[web]
     * -- [移动端](app,小程序等手机端应用)统一添加[api]
     * -- 方便做统一的权限管理,
     *
     * @param configurer
     */
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        configurer
                // Feign端 统一加入 前缀
                .addPathPrefix(FeignController.PATH_PREFIX, o -> Objects.equals(o.getSuperclass(), FeignController.class))
                // 外部端 统一加入 前缀
                .addPathPrefix(ExternalController.PATH_PREFIX, o -> Objects.equals(o.getSuperclass(), ExternalController.class))
                // 电脑端 统一加入 前缀
                .addPathPrefix(WebController.PATH_PREFIX, o -> Objects.equals(o.getSuperclass(), WebController.class))
                // 移动端 统一加入 前缀
                .addPathPrefix(ApiController.PATH_PREFIX, o -> Objects.equals(o.getSuperclass(), ApiController.class));
    }


}